#pragma once

#include "RedefinableElement.h"

#include "Classifier.h"

namespace uml {

const bool RedefinableElement::isLeaf_default_ = false;
void RedefinableElement::fromJson(const QJsonObject& json, QStringList& errorList) {
    if (json.isEmpty()) {
        return;
    }

    PartialElement::fromJson(json, errorList);
    isLeaf_ = json.value("isLeaf").toBool(isLeaf_default_);
    JsonSerializable::fromJsonArray(redefinedElements_, "redefinedElements", json, errorList);
    JsonSerializable::fromJsonArray(redefinitionContexts_, "redefinitionContexts", json, errorList);
}

void RedefinableElement::toJson(QJsonObject& json) {
    PartialElement::toJson(json);
    if (isLeaf_ != isLeaf_default_) {
        json.insert("isLeaf", isLeaf_);
    }
    JsonSerializable::toJsonArray(redefinedElements_, "redefinedElements", json);
    JsonSerializable::toJsonArray(redefinitionContexts_, "redefinitionContexts", json);
}

/// <summary>
/// isConsistentWith
    /// The query isConsistentWith() specifies, for any two RedefinableElements in a
    /// context in which redefinition is possible, whether redefinition would be
    /// logically consistent. By default, this is false; this operation must be
    /// overridden for subclasses of RedefinableElement to define the consistency
    /// conditions.
/// </summary>
    /// <code>
    /// result = (false)
    /// </code>
    /// <code>
    /// redefiningElement.isRedefinitionContextValid(self)
    /// </code>
bool RedefinableElement::isConsistentWith(shared_ptr<RedefinableElement> redefiningElement) const
{
    return false;
}

/// <summary>
/// isRedefinitionContextValid
    /// The query isRedefinitionContextValid() specifies whether the redefinition
    /// contexts of this RedefinableElement are properly related to the redefinition
    /// contexts of the specified RedefinableElement to allow this element to redefine
    /// the other. By default at least one of the redefinition contexts of this element
    /// must be a specialization of at least one of the redefinition contexts of the
    /// specified element.
/// </summary>
    /// <code>
    /// result = (redefinitionContext->exists(c | c.allParents()->includesAll(redefinedElement.redefinitionContext)))
    /// </code>
bool RedefinableElement::isRedefinitionContextValid(shared_ptr<RedefinableElement> redefinedElement) const
{
    return false;
}

/// <summary>
/// isLeaf getter
/// Indicates whether it is possible to further redefine a RedefinableElement. If
/// the value is true, then it is not possible to further redefine the
/// RedefinableElement.
/// </summary>
bool RedefinableElement::isLeaf() const {
    return isLeaf_;
}

/// <summary>
/// isLeaf setter
/// Indicates whether it is possible to further redefine a RedefinableElement. If
/// the value is true, then it is not possible to further redefine the
/// RedefinableElement.
/// </summary>
void RedefinableElement::setIsLeaf(bool value) {
    isLeaf_ = value;
}

/// <summary>
/// redefinedElements getter
/// The RedefinableElement that is being redefined by this element.
/// </summary>
vector<shared_ptr<RedefinableElement>>& RedefinableElement::redefinedElements() {
    return redefinedElements_;
}

/// <summary>
/// redefinitionContexts getter
/// The contexts that this element may be redefined from.
/// </summary>
vector<shared_ptr<Classifier>>& RedefinableElement::redefinitionContexts() {
    return redefinitionContexts_;
}

} // namespace uml
